import json
import logging
import queue
import socket
import sys
import time
from collections import Counter
from threading import Thread, Event
from PIL import Image
from io import BytesIO
from flask_cors import CORS


# from OpenSSL.rand import status
from flask import Flask, Response, request,redirect,url_for,send_file
from flask_cors import CORS
from dataStore import GlobalVar
from util import get_camera_list
from SubFunction import *
from inference import GenModule

logger = logging.getLogger("yolov5")
logger.setLevel(level=logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)

logger.addHandler(handler)
logger.addHandler(console)

import configparser
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
cf = configparser.ConfigParser()
cf.read(os.path.join(BASE_DIR,"config.ini"), encoding='UTF-8')
front_weight=cf.get("weight","front_weight")
back_weight=cf.get("weight","back_weight")


def save_image_from_bytes(byte_stream, output_path):
    # 将字节流转换为图像
    image = Image.open(BytesIO(byte_stream))
    # 保存图像到指定路径
    image.save(output_path)


class Appfront:
    def __init__(self,gpu_id):
        self.app=Flask(__name__)
        self.setup_routes()
        CORS(self.app)
        self.program={}
        self.send_data = None
        self.personTrack = False
        self.src_list=[]
        self.exe_camera_list=[]
        # self.imagesize = 640
        self.imagesize = 1280
        self.is_class = 0
        self.person_type=1
        self.device=gpu_id
        self.camera_list = []
        self.interval_frame=0
        self.camera_map = {}
        self.thread_wait = False
        self.started_evt = Event()
        self.hoisting=None
        self.frameNum=1
        self.stu_port=0
        self.func_dict= {
        '1': GenModule,  # 学生
        '2': GenModule,  # 教师
    }
        self.weights_dict = {
            '1': [os.path.join(BASE_DIR,front_weight)],
            '2': [os.path.join(BASE_DIR,back_weight)],
        }

    def run(self, host, port):
        print("app")
        self.stu_port=int(port)
        print(self.stu_port)
        self.app.run(host=host, port=port)

    # 队列做
    # def gen1(self,camera_id,type):
    #     while True:
    #         if len(self.camera_map) != 0:
    #             # queue_length = self.camera_map[type].qsize()
    #             # print("摄像头{}前-->队列的长度为{}:".format(camera_id,queue_length))
    #             # if queue_length <= 5:
    #             #     # time.sleep(0.3)
    #             #     pass
    #             frame = self.camera_map[type].get()
    #             # time.sleep(0.15)
    #             # queue_length = self.camera_map[type].qsize()
    #             # print("摄像头{}后-->队列的长度为{}:".format(camera_id,queue_length))
    #         else:
    #             frame = 2
    #             frame.to_bytes(4, byteorder='little', signed=True)
    #         # 使用generator函数输出视频流， 每次请求输出的content类型是image/jpeg
    #         # print(frame)
    #         yield (b'--frame\r\n'
    #                b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')



    # 没有队列
    def gen1(self, camera_id,type):
        while True:
            if len(self.camera_map) != 0:
                # if self.secret == False:
                # time.sleep(0.15)
                frame = self.camera_map[type]
                # save_image_from_bytes(frame,f"./pic/img{pic}.jpg")
                # pic += 1
            else:
                frame = 2
                frame.to_bytes(4, byteorder='little', signed=True)
                # time.sleep(0.1)
            # 使用generator函数输出视频流， 每次请求输出的content类型是image/jpeg
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
    # 有队列
    # def workThred(self,hoisting, person_type, started_evt):
    #     print('countdown starting')
    #     data_store = GlobalVar()
    #     # import websockets
    #     for i in self.camera_list:
    #         self.camera_map[f"gas:video:{i}:name"] = queue.Queue()
    #
    #     while True:
    #         if self.thread_wait:
    #             started_evt.wait()
    #             # print("主线程暂停")
    #             continue
    #         start_time = time.time()
    #         # 检测每一帧的检测结果[L,NL]
    #         hoisting.execute_func()
    #
    #         # 每一帧的画面
    #         for key,value in hoisting.camera_map.items():
    #             self.camera_map[key].put(value)
    #         # self.camera_map = hoisting.camera_map
    #         # queue_length = self.camera_map[f"gas:video:{self.camera_list[0]}:name"].qsize()
    #         # print("112-->队列的长度为:", queue_length)
    #         # if(queue_length == 30):
    #         for key, value in hoisting.camera_map.items():
    #             if self.camera_map[key].qsize() >= 5:
    #                 self.camera_map[key].get()
    #         hoisting.class_is = self.is_class
    #         # 判断是否上下课，并发送图片
    #         if hoisting.class_is == 1: # 下课
    #             hoisting.clear_variable()
    #             self.is_class = 0
    #         if hoisting.class_is == 2:
    #             if person_type == '2': # 上课
    #                 hoisting.send_points()
    #             self.is_class = 0
    #
    #         # Thread(target=hoisting.senf_m).start()
    #         # hoisting.senf_m()
    #         end_time = round(time.time() - start_time, 3)
    #         # self.frameNum = self.frameNum + 1
    #         # print(f"第{self.frameNum - 1}帧")
    #         # print("帧总的推理时间：", end_time)
    #         # else:
    #         #     print("网络已中断，请检测网络连接................")

    # 无队列
    def workThred(self,hoisting, person_type, started_evt):
        print('countdown starting')

        while True:
            if self.thread_wait:
                started_evt.wait()
                # print("主线程暂停")
                continue
            # 检测每一帧的检测结果[L,NL]
            # cu_time=time.time()
            hoisting.execute_func()
            # time.sleep(hoisting.sleeptime)
            self.camera_map = hoisting.camera_map
            # print("appFront消耗时间:",time.time()-cu_time)
            # queue_length = self.camera_map[f"gas:video:{self.camera_list[0]}:name"].qsize()
            # print("112-->队列的长度为:", queue_length)
            # if(queue_length == 30):
            hoisting.class_is = self.is_class
            # 判断是否上下课，并发送图片
            if hoisting.class_is == 1: # 下课
                hoisting.clear_variable()
                self.is_class = 0
            if hoisting.class_is == 2:
                if person_type == '2': # 上课
                    hoisting.send_points()
                self.is_class = 0

            # Thread(target=hoisting.senf_m).start()
            # hoisting.senf_m()
            # end_time = round(time.time() - start_time, 3)

    def workthread1(self,hoisting, names):
        while True:
            hoisting.resutl_save(names)


    def workthread2(self,hoisting):
        while True:
            hoisting.save_img()
    def common_fun(self,hoisting, person_type):
        self.hoisting=hoisting
        print("开始执行")
        t = Thread(target=self.workThred, args=(hoisting, person_type, self.started_evt), daemon=True)
        t.start()
        print('countdown is running')
        data = {
            "code": 200
        }
        return json.dumps(data)
    def setup_routes(self):
        @self.app.route('/isLive',methods=['GET', 'POST'])#判断这个flask进程是否存在
        def is_live():
            data = {
                "code": 200,
                "msg": "isLive",
                "data": {}
            }
            return json.dumps(data)
        @self.app.route('/get_stream', methods=['GET', 'POST'])  # 这个地址返回视频流响应
        def test_redis():
            # gas: video:1: name
            alarm_type = request.args.get("type")
            print("视频流参数：", alarm_type)
            camera_id=alarm_type.split("gas:video:")[1].split(":")[0]
            # # print("=========",self.hoisting.camera_list)
            # suoyi=self.hoisting.camera_list.index(int(camera_id))
            # self.hoisting.tuiliu[suoyi]=True
            return Response(self.gen1(camera_id,alarm_type), mimetype='multipart/x-mixed-replace; boundary=frame')

        @self.app.route('/open_get_stream', methods=['GET', 'POST'])  # 这个地址返回视频流响应
        def open_stream():
            data = request.get_data()
            data=json.loads(data)
            camera_id=data['camera_id']
            suoyi=self.hoisting.camera_list.index(int(camera_id))
            self.hoisting.tuiliu[suoyi]=True
            return {
                "code": 200,
                "msg": "success",
                "data": {}
            }

        @self.app.route('/shutdown_get_stream', methods=['GET', 'POST'])  # 这个地址返回视频流响应
        def shutdown_stream():
            data = request.get_data()
            data=json.loads(data)
            camera_id=data['camera_id']
            suoyi=self.hoisting.camera_list.index(int(camera_id))
            self.hoisting.tuiliu[suoyi]=False
            return {
                "code": 200,
                "msg": "success",
                "data": {}
            }
        @self.app.route('/get_person_num', methods=['GET', 'POST'])
        def get_person_num():
            sumNum = GlobalVar().numCount(GlobalVar.detectionRes[-1]["detectRes"])
            data = {"code": 200, "msg": "success", "data": sumNum}
            return json.dumps(data)

        @self.app.route('/class_begin', methods=['GET'])
        def class_begin():
            self.is_class = 1
            data = {
                "code": 200,
                "msg": "success",
                "data": {}
            }
            return json.dumps(data)


        @self.app.route('/class_end', methods=['GET'])
        def class_end():
            self.is_class = 2
            data = {
                "code": 200,
                "msg": "success",
                "data": {}
            }
            return json.dumps(data)

        @self.app.route('/getBehaviorNum', methods=['GET', 'POST'])
        def getbehaviornum():

            actions_data = GlobalVar().actionNum()
            viedo_frame = list(actions_data.keys())[0]
            actions_num = list(actions_data.values())[0]
            print("-------正在统计当前人数--------")
            data = {"code": 200, "msg": "retrieved the data", "data": actions_num}
            return json.dumps(data)

        @self.app.route('/stop', methods=["GET"])  # 这个地址返回视频流响应
        def stop():
            self.thread_wait = True
            print("结束执行")
            data = {
                "code": 200,
                "msg": "算法结束",
                "data": {}
            }
            return json.dumps(data)

        @self.app.route('/recover', methods=['GET'])
        def recover():
            self.started_evt.set()
            self.thread_wait=False
            data = {
                "code": 200,
                "msg": "主线程恢复",
                "data": {}
            }
            print("主线程恢复")
            return json.dumps(data)
        # 支持每秒分析图像不少于5帧
        @self.app.route('/calculateFiveFrameTime', methods=['POST', 'GET'])
        def calculatFiveFrameTime():
            frame500_detect_time = GlobalVar.Frame500_detect_time
            print(frame500_detect_time)
            if frame500_detect_time == 0:
                return "稍等一下，马上计算出来..."
            return "1秒钟检测帧数量为：" + str(round((500 / int(frame500_detect_time))))

        # 40分钟内课程内模型分析识别不少于10000帧
        @self.app.route('/calculate_10000_FrameTime', methods=['POST', 'GET'])
        def calculate_10000_FrameTime():
            time_10000_frame_detect = GlobalVar.Frame10000_detect_time
            if time_10000_frame_detect == 0:
                return "10000帧还没检测到，稍等片刻..."
            return "10000帧检测帧时间为：" + str(round(time_10000_frame_detect / 60)) + "分钟"


        @self.app.route('/start', methods=['POST', 'GET', 'OPTIONS'])  # 这个地址返回视频流响应
        def start():
            # if request.method == 'OPTIONS':
            #     # 处理 OPTIONS 请求
            #     response_headers = {
            #         'Access-Control-Allow-Origin': '*',
            #         'Access-Control-Allow-Methods': 'POST',
            #         'Access-Control-Allow-Headers': 'Content-Type'
            #     }
            #     return ('', 204, response_headers)

            # data = request.json
            # print(data)
            # return 0
            data = request.get_data()
            # data=get_camera_list(self.stu_port)  #正式运行时打开这个，从后端获取视频流数据
            # print(data)
            data = json.loads(data)
            # print("data:::::::::::;",gen type(data))
            # "path": "rtsp://admin:zy123456@172.27.169.14:554",
            # "path": "./_lock/ketang_front.mp4",
            # data = [
            #     {
            #         "path": "rtsp://admin:zy123456@172.27.169.14:554",
            #         "camera_id": 3,
            #         "person_type": 1
            #     },
            #     {
            #         "path": "rtsp://admin:zy123456@172.27.169.14:554",
            #         "camera_id": 4,
            #         "person_type": 1
            #     },
            #     {
            #         "path": "rtsp://admin:zy123456@172.27.224.95:554",
            #         "camera_id": 5,
            #         "person_type": 1
            #     }
            # ]
            for data_in in data:
                if data_in['camera_id'] not in self.camera_list:
                    self.src_list.append(data_in['path'])
                    self.camera_list.append(data_in['camera_id'])
                    self.exe_camera_list.append(data_in['camera_id'])
                    self.person_type = data_in["person_type"]
            if len(self.exe_camera_list) > 0:
                if self.person_type == 1:
                    self.interval_frame = 0  # 跳帧检测
                Func = self.func_dict[str(self.person_type)]  # 类
                print(self.weights_dict[str(self.person_type)])
                sub_weight = self.weights_dict[str(self.person_type)]  # 权重
                sub_addr = self.src_list
                params = {
                    "camera_id": 0,
                    "location":"classroom_back" ,
                    "created_at": "",
                    "data_id": "",
                    "event_level": "",
                    "event_type": "",
                    "total_people": 0,
                    "trajectory":[],
                    "screenshot_url": "",
                    "video_url": ""
                }
                sub_func = GenModule(src_list=sub_addr,  # 视频源
                                     weight=sub_weight,  # 权重
                                     params=params,
                                     stu_port=self.stu_port,
                                     fps_show=False,  # fps显示 # 丢帧模拟
                                     track=self.personTrack,  # 跟踪
                                     msg_send=True,  # 警报发送
                                     imagesize=self.imagesize,
                                     half=True,
                                     camera_list=self.exe_camera_list,  # 摄像头数组
                                     Time_time=self.interval_frame,  # 隔多少帧检测一次
                                     device=self.device,
                                     COUNTS=5,  # 间隔30帧
                                     FramesListening=60,  # 听讲人数，间隔5秒
                                     FramesPeople=1,  # 教室人数，间隔一分钟
                                     # secret=False
                                     )
                status = self.common_fun(hoisting=sub_func, person_type=self.person_type)

                return status
if __name__ == '__main__':
    gpu_id = sys.argv[1]
    host=sys.argv[2]
    port=sys.argv[3]
    # gpu_id = 0
    # host='0.0.0.0'
    # port=5000
    Appfront(gpu_id).run(host=host, port=port)

